package bb.lanxing.lib.devices.sprint.utils

import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.util.Log
import bb.lanxing.lib.base.BaseApplication
import bb.lanxing.lib.devices.api.DeviceManager
import bb.lanxing.lib.devices.sprint.utils.XossDeviceConnector.ConnectListener
import com.clj.fastble.BleManager
import com.clj.fastble.callback.BleGattCallback
import com.clj.fastble.data.BleDevice
import com.clj.fastble.exception.BleException

object BleBondUtil {
    private val boundedDevice: List<BluetoothDevice>
        get() {
            val bondedDevices = BluetoothAdapter.getDefaultAdapter().bondedDevices
            return bondedDevices.toList().filterNotNull()
        }

    fun isThisDeviceBounded(address: String?): Boolean {
        var obj: BluetoothDevice?
        val it = boundedDevice.iterator()
        while (true) {
            if (!it.hasNext()) {
                obj = null
                break
            }
            obj = it.next()
            if (obj.address == address) {
                break
            }
        }
        if (null != obj) {
            return ensureBonded(obj)
        }
        return false
    }

    fun getBoundedDevice(address: String?): BluetoothDevice? {
        var obj: BluetoothDevice?
        val it = boundedDevice.iterator()
        while (true) {
            if (!it.hasNext()) {
                obj = null
                break
            }
            obj = it.next()
            if (obj.address == address) {
                break
            }
        }
        return obj
    }


    fun ensureBonded(bluetoothDevice: BluetoothDevice): Boolean {
        val boundedDevice = getBoundedDevice(bluetoothDevice.address)
        return boundedDevice != null && boundedDevice.bondState == 12
    }

    fun createBondByConnect(
        device: BluetoothDevice,
        connectStart: () -> Unit,
        connectFailed: () -> Unit,
        connectSuccess: (BluetoothGatt) -> Unit
    ) {
        BleManager.getInstance().connect(device.address, object : BleGattCallback() {
            override fun onDisConnected(
                z: Boolean, bleDevice: BleDevice, bluetoothGatt: BluetoothGatt, i: Int
            ) {
            }

            override fun onStartConnect() {
                connectStart.invoke()
            }

            override fun onConnectFail(bleDevice: BleDevice, bleException: BleException) {
                connectFailed.invoke()
            }

            override fun onConnectSuccess(
                bleDevice: BleDevice, bluetoothGatt: BluetoothGatt, i: Int
            ) {
                connectSuccess.invoke(bluetoothGatt)
            }
        })
    }

    fun createBondByConnect(
        deviceManager: DeviceManager?,
        device: BluetoothDevice,
        i: Int,
        connectStart: () -> Unit,
        connectFailed: () -> Unit,
        connectSuccess: () -> Unit
    ) {
        val xossDeviceConnector = XossDeviceConnector(false, 1, null)
        val address = device.address
        val name = device.name
        xossDeviceConnector.connect(deviceManager, address, name, i, object : ConnectListener {
            override fun onConnecting() {
                connectStart.invoke()
            }

            override fun onConnected() {
                connectSuccess.invoke()
            }

            override fun onConnectFailed() {
                connectFailed.invoke()
            }
        })
    }

    fun createBond(device: BluetoothDevice): Boolean {
        Log.d("BleBondUtil", "device.createBond()")
        return device.createBond()
    }

    fun internalRemoveBond(device: BluetoothDevice): Boolean {
        Log.e("BleBondUtil", "Removing bond information...")
        if (device.bondState == 10) {
            return true
        }
        try {
            val method = device.javaClass.getMethod("removeBond", *arrayOfNulls(0))
            Log.d("BleBondUtil", "device.removeBond() (hidden)")
            val invoke = method.invoke(device, *arrayOfNulls(0))
            Log.d("BleBondUtil", "Remove bond result: $invoke")
            return invoke == true
        } catch (unused: Exception) {
            Log.d("BleBondUtil", "An exception occurred while removing bond")
            return false
        }
    }
}
